package com.zxy.ziems.server.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zxy.btp.common.exception.ConditionException;
import com.zxy.btp.common.response.PageResult;
import com.zxy.ziems.server.constant.PointDataType;
import com.zxy.ziems.server.constant.enums.PointStatusEnum;
import com.zxy.ziems.server.convert.PointConvert;
import com.zxy.ziems.server.domain.ClassifyPointRel;
import com.zxy.ziems.server.domain.Dept;
import com.zxy.ziems.server.domain.Point;
import com.zxy.ziems.server.domain.Role;
import com.zxy.ziems.server.domain.User;
import com.zxy.ziems.server.dto.PointDto;
import com.zxy.ziems.server.dto.PointQueryDto;
import com.zxy.ziems.server.mapper.PointMapper;
import com.zxy.ziems.server.service.ClassifyPointRelService;
import com.zxy.ziems.server.service.DeptService;
import com.zxy.ziems.server.service.PointService;
import com.zxy.ziems.server.service.UserService;
import com.zxy.ziems.server.vo.PointVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @ClassName PointServiceImpl
 * @Description
 * @Author 邓伟
 * @Date 2023/11/23 16:28
 * @Version 1.0
 */
@Service
public class PointServiceImpl extends ServiceImpl<PointMapper, Point> implements PointService {

    @Autowired
    private PointMapper pointMapper;
    @Autowired
    private DeptService deptService;
    @Autowired
    private UserService userService;
    @Autowired
    private ClassifyPointRelService classifyPointRelService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addOrUpdate(PointDto pointDto) {
        //校验点位名称和编码
        String pointId = pointDto.getPointId();
        checkPointCodeAndName(pointDto);
        Point point = PointConvert.INSTANCE.pointDtoToPoint(pointDto);
        if (StrUtil.isEmpty(pointId)) {
            point.setPointStatus(PointStatusEnum.START.code());
            pointMapper.insert(point);
        }else {
            pointMapper.updateById(point);
        }
    }

    private void checkPointCodeAndName(PointDto pointDto) {
        String pointId = pointDto.getPointId();
        QueryWrapper<Point> queryCode = new QueryWrapper<>();
        queryCode.lambda().eq(Point::getPointCode,pointDto.getPointCode());
        if (StrUtil.isNotEmpty(pointId)) {
            queryCode.lambda().ne(Point::getPointId,pointId);
        }
        Long countCode = pointMapper.selectCount(queryCode);
        if (countCode > 0 ) {
            throw new ConditionException("点位编码不能重复");
        }
        queryCode.clear();
        queryCode.lambda().eq(Point::getPointName,pointDto.getPointName());
        if (StrUtil.isNotEmpty(pointId)) {
            queryCode.lambda().ne(Point::getPointId,pointId);
        }
        Long countName = pointMapper.selectCount(queryCode);
        if (countName > 0 ) {
            throw new ConditionException("点位名称不能重复");
        }
    }

    @Override
    public void startOrStop(PointDto pointDto) {
        Integer status = pointDto.getPointStatus();
        if (ObjectUtil.isEmpty(status)) {
            throw new ConditionException("状态不能为空");
        }
        String pointId = pointDto.getPointId();
        if (StrUtil.isEmpty(pointId)) {
            throw new ConditionException("点位id不能为空");
        }
        Point point = new Point();
        point.setPointId(pointId);
        point.setPointStatus(status);
        pointMapper.updateById(point);
    }

    @Override
    @Transactional(readOnly = true)
    public PageResult<PointVo> pageList(PointQueryDto pointQueryDto) {
        Page<Point> page = new Page<>(pointQueryDto.getPageNo(), pointQueryDto.getPageSize());
        QueryWrapper<Point> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().like(StrUtil.isNotEmpty(pointQueryDto.getPointName()),Point::getPointName,pointQueryDto.getPointName())
                .eq(StrUtil.isNotEmpty(pointQueryDto.getEnergyType()),Point::getEnergyType,pointQueryDto.getEnergyType())
                .eq(ObjectUtil.isNotEmpty(pointQueryDto.getDataObtainType()),Point::getDataObtainType,pointQueryDto.getDataObtainType());
        Integer dataType = pointQueryDto.getDataType();
        if (ObjectUtil.isNotEmpty(dataType)) {
            if (0 == dataType) {
                queryWrapper.lambda().eq(Point::getDataObtainType, PointDataType.AUTO);
            }else {
                queryWrapper.lambda().in(Point::getDataObtainType,PointDataType.HAND_DAY,PointDataType.HAND_MONTH);
            }
        }

        Integer queryType = pointQueryDto.getQueryType();
        if (ObjectUtil.isNotEmpty(queryType)) {
            String classifyId = pointQueryDto.getClassifyId();
            String rootClassifyId = pointQueryDto.getRootClassifyId();
            if (0 == queryType && StrUtil.isNotEmpty(classifyId)) {
                //查询关联表数据
                QueryWrapper<ClassifyPointRel> query = new QueryWrapper<>();
                query.lambda().eq(ClassifyPointRel::getClassifyId,classifyId);
                List<ClassifyPointRel> relList = classifyPointRelService.list(query);
                if (CollectionUtil.isEmpty(relList)) {
                    return new PageResult<>(0L,null);
                }
                queryWrapper.lambda().in(Point::getPointId,relList.stream().map(ClassifyPointRel::getPointId).toList())
                        .orderByAsc(Point::getSort);
            }else if (1 == queryType && StrUtil.isNotEmpty(rootClassifyId)){
                //查询未关联此大类的数据
                QueryWrapper<ClassifyPointRel> query = new QueryWrapper<>();
                query.lambda().eq(ClassifyPointRel::getRootClassifyId,rootClassifyId);
                List<ClassifyPointRel> relList = classifyPointRelService.list(query);
                if (CollectionUtil.isNotEmpty(relList)) {
                    queryWrapper.lambda().notIn(Point::getPointId,relList.stream().map(ClassifyPointRel::getPointId).toList());
                }
                queryWrapper.lambda().orderByAsc(Point::getSort);
            }
        }else {
            queryWrapper.lambda().orderByDesc(Point::getUpdateTime);
        }
        Page<Point> pageData = pointMapper.selectPage(page, queryWrapper);
        List<Point> pointList = pageData.getRecords();
        if (CollectionUtil.isEmpty(pointList)) {
            return new PageResult<>(0L,null);
        }
        List<PointVo> pointVoList = PointConvert.INSTANCE.pointListToPointVoList(pointList);
        List<String> deptIdList = pointVoList.stream().map(PointVo::getDeptId).toList();
        if (CollectionUtil.isNotEmpty(deptIdList)) {
            List<Dept> deptList = deptService.listByIds(deptIdList);
            Map<String, String> deptMap = deptList.stream().collect(Collectors.toMap(Dept::getDeptId, Dept::getDeptName));
            for (PointVo pointVo : pointVoList) {
                String deptId = pointVo.getDeptId();
                if (StrUtil.isNotEmpty(deptId)) {
                    pointVo.setDeptName(deptMap.get(deptId));
                }
            }
        }
        //查询更新人姓名
        List<String> userIdList = pointVoList.stream().map(PointVo::getUpdateUserId).toList();
        List<User> userList = userService.listByIds(userIdList);
        if (CollectionUtil.isNotEmpty(userList)) {
            Map<String, String> userMap = userList.stream().collect(Collectors.toMap(User::getUserId, User::getUserName));
            for (PointVo pointVo : pointVoList) {
                String userId = pointVo.getUpdateUserId();
                if (StrUtil.isNotEmpty(userId)) {
                    pointVo.setUpdateUserName(userMap.get(userId));
                }
            }
        }
        return new PageResult<>(pageData.getTotal(),pointVoList);
    }

    @Override
    public void delete(String pointId) {
        //todo 判断是否关联数据分类
        //删除
        removeById(pointId);
    }
}
